package com.witmore.skyline.db.mapper;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.witmore.skyline.db.entity.DeviceDO;
import com.witmore.skyline.db.mapper.dto.DeviceCategoryResultDTO;
import com.witmore.skyline.db.mapper.dto.DeviceListQueryDTO;
import com.witmore.skyline.db.mapper.dto.DeviceMapStatisticsResultDTO;
import com.witmore.skyline.db.mapper.dto.ProjectDeviceDetailDTO;
import com.witmore.skyline.db.mapper.dto.ProjectDeviceWorkDaysDTO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 设备表 Mapper 接口
 * </p>
 *
 * @author 豆子高
 * @since 2025-02-24
 */
@Mapper
public interface DeviceMapper extends BaseMapper<DeviceDO> {


    Page<DeviceDO> selectPageCustom(Page<DeviceDO> page, @Param("deviceListQueryDTO") DeviceListQueryDTO deviceListQueryDTO);

    int selectCustomCount(@Param("deviceListQueryDTO") DeviceListQueryDTO deviceListQueryDTO);


    /**
     * 统计负荷工作时长超过指定时间的设备数量
     * 使用 MyBatis-Plus 默认实现
     */
    default int selectLoadWorkingCount(Integer orgId, List<Integer> businessIdList, double loadWorkTime) {
        LambdaQueryWrapper<DeviceDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeviceDO::getIsDeleted, 0)
               .eq(DeviceDO::getOrgId, orgId)
               .ge(DeviceDO::getLoadWorkTime, loadWorkTime)
               .in(businessIdList != null && !businessIdList.isEmpty(), DeviceDO::getId, businessIdList);
        return Math.toIntExact(this.selectCount(wrapper));
    }

    /**
     * 统计负荷工作时长小于指定时间的设备数量
     * 使用 MyBatis-Plus 默认实现
     */
    default int selectUnWorkingCount(Integer orgId, List<Integer> businessIdList, double loadWorkTime) {
        LambdaQueryWrapper<DeviceDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeviceDO::getIsDeleted, 0)
               .eq(DeviceDO::getOrgId, orgId)
               .and(w -> w.isNull(DeviceDO::getLoadWorkTime)
                          .or()
                          .lt(DeviceDO::getLoadWorkTime, loadWorkTime))
               .in(businessIdList != null && !businessIdList.isEmpty(), DeviceDO::getId, businessIdList);
        return Math.toIntExact(this.selectCount(wrapper));
    }

    List<DeviceCategoryResultDTO> deviceCategoryDistribution(@Param("orgId") Integer orgId, @Param("deviceIds") List<Integer> deviceIds);


    List<DeviceMapStatisticsResultDTO> deviceMapStatistics(@Param("orgId") Integer orgId);

    /**
     * 查询当天各项目部的设备详细信息（用于去重）
     * @param orgId 企业ID
     * @return 项目部设备详细信息列表
     */
    List<ProjectDeviceDetailDTO> selectTodayProjectDeviceDetails(@Param("orgId") Integer orgId);

    /**
     * 查询当天各项目部的施工设备详细信息（负荷工作时间超过阈值，用于去重）
     * @param orgId 企业ID
     * @param loadWorkTime 负荷工作时间阈值
     * @return 项目部设备详细信息列表
     */
    List<ProjectDeviceDetailDTO> selectTodayProjectDeviceWorkingDetails(@Param("orgId") Integer orgId, @Param("loadWorkTime") double loadWorkTime);

    /**
     * 查询当天各项目部设备的施工天数统计（用于计算开工率）
     * @param orgId 企业ID
     * @param loadWorkTime 负荷工作时间阈值
     * @return 项目部设备施工天数统计列表
     */
    List<ProjectDeviceWorkDaysDTO> selectTodayProjectDeviceWorkDays(@Param("orgId") Integer orgId, @Param("loadWorkTime") double loadWorkTime);

    /**
     * 统计有施工设备的项目数量（通用方法）
     * 使用 MyBatis-Plus 默认实现，直接从设备表查询不重复的项目ID
     *
     * @param orgId 企业ID（可选）
     * @param projectIds 项目ID列表（可选）
     * @param province 省份（可选）
     * @param city 城市（可选）
     * @param loadWorkTime 负荷工作时间阈值
     * @return 施工项目数量
     */
    default int selectWorkingProjectCount(Integer orgId, List<Integer> projectIds, String province, String city, double loadWorkTime) {
        LambdaQueryWrapper<DeviceDO> wrapper = new LambdaQueryWrapper<DeviceDO>()
                .eq(DeviceDO::getIsDeleted, 0)
                .ge(DeviceDO::getLoadWorkTime, loadWorkTime)
                .isNotNull(DeviceDO::getProjectId)
                .eq(DeviceDO::getOrgId, orgId)
                .in(projectIds != null && !projectIds.isEmpty(), DeviceDO::getProjectId, projectIds)
                .eq(StringUtils.hasText(province), DeviceDO::getProvince, province)
                .eq(StringUtils.hasText(city), DeviceDO::getCity, city);

        return (int) this.selectList(wrapper).stream()
                .map(DeviceDO::getProjectId)
                .filter(Objects::nonNull)
                .distinct()
                .count();
    }


}
